var groupLib = require('group-array');

// given an array of object, like blog posts...
var arr = [
  { data: { year: '2016', tag: 'one', month: 'jan', day: '01'}, content: '...'},
  { data: { year: '2016', tag: 'one', month: 'jan', day: '01'}, content: '...'},
  { data: { year: '2016', tag: 'one', month: 'jan', day: '02'}, content: '...'},
  { data: { year: '2016', tag: 'one', month: 'jan', day: '02'}, content: '...'},
  { data: { year: '2016', tag: 'one', month: 'feb', day: '10'}, content: '...'},
  { data: { year: '2016', tag: 'one', month: 'feb', day: '10'}, content: '...'},
  { data: { year: '2016', tag: 'one', month: 'feb', day: '12'}, content: '...'},
  { data: { year: '2016', tag: 'one', month: 'feb', day: '12'}, content: '...'},
  { data: { year: '2016', tag: 'two', month: 'jan', day: '14'}, content: '...'},
  { data: { year: '2016', tag: 'two', month: 'jan', day: '14'}, content: '...'},
  { data: { year: '2016', tag: 'two', month: 'jan', day: '16'}, content: '...'},
  { data: { year: '2016', tag: 'two', month: 'jan', day: '16'}, content: '...'},
  { data: { year: '2016', tag: 'two', month: 'feb', day: '18'}, content: '...'},
  { data: { year: '2017', tag: 'two', month: 'feb', day: '18'}, content: '...'},
  { data: { year: '2017', tag: 'two', month: 'feb', day: '10'}, content: '...'},
  { data: { year: '2017', tag: 'two', month: 'feb', day: '10'}, content: '...'},
  { data: { year: '2017', tag: 'three', month: 'jan', day: '01'}, content: '...'},
  { data: { year: '2017', tag: 'three', month: 'jan', day: '01'}, content: '...'},
  { data: { year: '2017', tag: 'three', month: 'jan', day: '02'}, content: '...'},
  { data: { year: '2017', tag: 'three', month: 'jan', day: '02'}, content: '...'},
  { data: { year: '2017', tag: 'three', month: 'feb', day: '01'}, content: '...'},
  { data: { year: '2017', tag: 'three', month: 'feb', day: '01'}, content: '...'},
  { data: { year: '2017', tag: 'three', month: 'feb', day: '02'}, content: '...'},
  { data: { year: '2017', tag: 'three', month: 'feb', day: '02'}, content: '...'}
]

var args = ['data.year', 'data.tag', 'data.month', 'data.day']


var ret = groupLib(arr, ... args);
var retStr = JSON.stringify(ret, null, 2);
console.log(retStr)

var ret = arrayGroup(arr, ... args);
var retStr = JSON.stringify(ret, null, 2);
console.log(retStr)




// // group by the `tag` property
// var ret = groupLib(arr,  ... args);
// console.log(Object.keys(ret))

// var retStr = JSON.stringify(ret, null, 2);
// console.log(retStr)
// console.log('-----------------------\n')
// var ret = arrayGroup(arr, ... args);
// console.log(Object.keys(ret))
// var retStr2 = JSON.stringify(ret, null, 2);
// console.log(retStr2)
// console.log('-------------------- ' + (retStr === retStr2)+ ' ------------------------\n')



function arrayGroup(arr) {
  if(!Array.isArray(arr)) {
    throw new TypeError('excepts an array')
  }

  if(arguments.length === 1) {
    return arr
  }

  var args = Array.prototype.slice.call(arguments, 1)
  // 分组的属性, 数组按照property进行分组
  var property = args[0]
  var groups = groupBy(arr, property)

  //一次处理后面的分组参数
  for(var i = 1; i < args.length; i++) {
    toGroup(groups, args[i]);
  }

  return groups;
}

/**
 * 对象或者数组的两种不同的遍历方式
 * @param  {[type]}   obj     [description]
 * @param  {Function} fn      [description]
 * @param  {[type]}   thisArg [description]
 * @return {[type]}           [description]
 */
function eachValue(obj, fn, thisArg) {
  if(Array.isArray(obj)) {
    for(var i = 0; i < obj.length; i++) {
      fn.call(thisArg, obj[i], i, obj)
    }
  } else {
    for(var i in obj) {
      fn.call(thisArg, obj[i], i, obj)
    }
  }
}


/**
 * 递归处理函数， 根据不同的参数数组/对象做不同的处理
 * 
 * @param  {[type]} groups [description]
 * @param  {[type]} prop   [description]
 * @return {[type]}        [description]
 */
function toGroup(groups, prop) {
  eachValue(groups, function(val, key) {
    if(Array.isArray(val)) {
        groups[key] = groupBy(val, prop)
      } else {
        groups[key] = toGroup(val, prop)
      }
  })
  return groups
}


/**
 * 将数组按照某一个元素进行分组
 *
 * @param  {[type]} arr  [description]
 * @param  {[type]} prop [description]
 * @return {[type]}      [description]
 */
function groupBy(arr, prop) {
  var obj = {}
  var one, propVal;
  for(var i = 0; i < arr.length; i++) {
    one = arr[i]
    propVal = one[prop]

    if(propVal == null) {
      continue
    }

    if(!obj[propVal]) {
      obj[propVal] = []
    }
    obj[propVal].push(one)

  }
  return obj
}



